package cn.edu.sjtu.se.dslab.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import cn.edu.sjtu.se.dslab.action.bean.PageBean;
import cn.edu.sjtu.se.dslab.auth.CommonVariableModel;
import cn.edu.sjtu.se.dslab.component.data.DataType;
import cn.edu.sjtu.se.dslab.component.data.DomainEntity;
import cn.edu.sjtu.se.dslab.component.method.ComponentInterface;
import cn.edu.sjtu.se.dslab.component.method.InterfaceMethod;
import cn.edu.sjtu.se.dslab.component.method.util.InterfaceGenerator;
import cn.edu.sjtu.se.dslab.exception.DBException;
import cn.edu.sjtu.se.dslab.service.IComponentInterfaceService;
import cn.edu.sjtu.se.dslab.service.IDataTypeService;
import cn.edu.sjtu.se.dslab.service.IDomainEntityService;
import cn.edu.sjtu.se.dslab.service.IInterfaceMethodService;
import cn.edu.sjtu.se.dslab.util.Const;
import cn.edu.sjtu.se.dslab.util.Util;

@Controller
@RequestMapping(value = "/interface")
public class InterfaceController {

	@Resource(name = "componentInterfaceService")
	IComponentInterfaceService componentInterfaceService;

	@Resource(name = "dataTypeService")
	IDataTypeService dataTypeService;

	@Resource(name = "interfaceMethodService")
	IInterfaceMethodService interfaceMethodService;

	@Resource(name= "interfaceGenerator")
	InterfaceGenerator interfaceGenerator;

	@Resource(name = "domainEntityService")
	IDomainEntityService domainEntityService;
	
	protected Logger logger = LoggerFactory.getLogger(getClass());

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView getComponentInterfaceList(
			@RequestParam(value = "pageNum", defaultValue = "1") int pageNUm)
			throws DBException {
		ModelAndView model = new ModelAndView();
		model.setViewName("interface");
		try {
			PageBean<ComponentInterface> bean = componentInterfaceService
					.getPageBean(pageNUm);
			model.addObject("bean", bean);
			return model;
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return model;
	}

	@RequestMapping(value = "/search", method = RequestMethod.POST)
	public ModelAndView searchMethodComponentList(String searchText) {
		ModelAndView model = new ModelAndView();
		model.setViewName("interface_nopage");
		try {
			List<ComponentInterface> list = componentInterfaceService
					.getComponentInterfaceByProperty(searchText);
			model.addObject("mylist", list);
			return model;
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return model;
	}
	
	@RequestMapping(value = "/{uri}", method = RequestMethod.GET)
	public ModelAndView getComponentInterfaceByUri(
			@PathVariable(value = "uri") String uri) {
		ModelAndView model = new ModelAndView();
		try {
			ComponentInterface cInterface = componentInterfaceService
					.getComponentInterfaceByUri(Const.URI_INTERFACE + ":" + uri);
			if (cInterface != null) {
				model.setViewName("interface_detail");
				model.addObject("item", cInterface);

				String interfaceName = Util.getInterfaceName(cInterface);
				String interfacePath = Const.INTERFACE_GENERATE_PATH
						+ interfaceName;
				String interfaceRealPath = Const.ABSOLUTE_GENERATE_PATH
						+ interfacePath;
				File file = new File(interfaceRealPath);
				// 如果interface对应的文件存在，即认为是最新的；每次修改interface，删除该文件（保证最新）
				if (!file.exists()) {
					// String templateFile = "src/test/java/interface.vm";
					interfaceGenerator.generateInterface(cInterface, interfaceRealPath);
				}
				StringBuffer codebBuffer = new StringBuffer();
				List<String> codeList = FileUtils.readLines(file);
				for (String string : codeList) {
					codebBuffer.append(string + "\n");
				}
				model.addObject("code", codebBuffer.toString());
			}
			return model;
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return model;
	}

	@RequestMapping(value = "/{uri}/download", method = RequestMethod.GET)
	public void downloadComponentInterfaceByUri(
			@PathVariable(value = "uri") String uri,
			HttpServletResponse response) throws FileNotFoundException,
			IOException {
		ComponentInterface cInterface = componentInterfaceService
				.getComponentInterfaceByUri(Const.URI_INTERFACE + ":" + uri);
		if (cInterface != null) {
			String interfaceName = Util.getInterfaceName(cInterface);
			String interfacePath = Const.INTERFACE_GENERATE_PATH
					+ interfaceName;
			String interfaceRealPath = Const.ABSOLUTE_GENERATE_PATH
					+ interfacePath;
			File file = new File(interfaceRealPath);

			// 如果interface对应的文件存在，即认为是最新的；每次修改interface，删除该文件（保证最新）
			if (!file.exists()) {
				// String templateFile = "src/test/java/interface.vm";
				interfaceGenerator.generateInterface(cInterface, interfaceRealPath);
			}
			InputStream is = new FileInputStream(file);
			// set content attributes for the response
			response.setContentType("application/octet-stream");
			response.setContentLength((int) file.length());
			// set headers for the response
			String headerKey = "Content-Disposition";
			String headerValue = String.format("attachment; filename=\"%s\"",
					interfaceName);
			response.setHeader(headerKey, headerValue);
			IOUtils.copy(is, response.getOutputStream());
			response.flushBuffer();
		}
	}
	
	@RequestMapping(value = "/{uri}/delete", method = RequestMethod.GET)
	public String deleteComponentInterfaceByUri(
			@PathVariable(value = "uri") String uri) throws IOException{
		logger.info("删除 component interface:" + new Date().toString()
				+ "----start");
		ComponentInterface cInterface = componentInterfaceService
				.getComponentInterfaceByUri(Const.URI_INTERFACE + ":" + uri);
		//接口更新删除相应的生成文件
		interfaceGenerator.deleteInterfaceFile(cInterface);
		componentInterfaceService.deleteComponentInterfaceByUri(Const.URI_INTERFACE + ":" + uri);
		logger.info("添加 component interface:" + new Date().toString()
				+ "----end");
		return "redirect:/interface";
	}
	
	@RequestMapping(value = "/{uri}/update", method = RequestMethod.GET)
	public ModelAndView updateComponentInterfaceByUri(
			@PathVariable(value = "uri") String uri) {
		ComponentInterface cInterface = componentInterfaceService
				.getComponentInterfaceByUri(Const.URI_INTERFACE + ":" + uri);
		ModelAndView model = new ModelAndView();
		if (cInterface != null) {			
			model.setViewName("update_interface");
//			List<DataType> typeList = dataTypeService.getDataTypeList();
//			model.addObject("typeList", typeList);
			List<DataType> _typeList = dataTypeService.getDataTypeList();
			List<DomainEntity> typeList = domainEntityService.getAllDomainEntity();
			typeList.addAll(_typeList);
			model.addObject("typeList", typeList);
			model.addObject("cInterface", cInterface);
			model.addObject("uri", uri);
			return model;
		}else {
			model.setViewName("error");
			return model;
		}
		
	}
	
	@RequestMapping(value = "/{uri}/update", method = RequestMethod.POST)
	public String updateComponentInterfaceByUri(
			@PathVariable(value = "uri") String uri,
			@RequestParam(required = true) String name,
			@RequestParam(required = false) String description,
			@RequestParam(required = false) String itype,
			@RequestParam(required = false) long[] re_type,
			@RequestParam(required = false) String[] f_name,
			@RequestParam(required = false) String[] f_params,
			@RequestParam(required = false ) String[] f_sig,
			@RequestParam(required = false) String[] f_params_id,
			@RequestParam(required = false) String[] f_description)throws FileNotFoundException,
			IOException  {
		logger.info("更新 component interface:" + new Date().toString()
				+ "----start");
		ComponentInterface temp = componentInterfaceService
				.getComponentInterfaceByUri(Const.URI_INTERFACE + ":" + uri);
		if (temp != null) {
			temp.setName(name);
			temp.setDescription(description);
			temp.setItype(itype);
			componentInterfaceService.updateComponentInterface(temp);
			//接口更新删除相应的生成文件
			interfaceGenerator.deleteInterfaceFile(temp);
			if (re_type != null && f_name != null && f_params != null
					&& f_description != null && re_type.length == f_name.length) {
				for (int i = 0; i < f_name.length; i++) {
					InterfaceMethod method = new InterfaceMethod();
					
					String[] params = f_params[i].split(";");
					StringBuffer paramBuffer = new StringBuffer();
					if (params!= null && params.length>0) {	
						paramBuffer.append(params[0]);
						for (int j = 1; j < params.length; j++) {
							paramBuffer.append(","+params[j].trim());
						}
					}
					method.setArguments(paramBuffer.toString());
					
					/**
					 * 当函数只有一个时，对于带有逗号的字段，springmvc会自动转为字符串，需要手动将其重新拼接
					 */
					if (f_name.length == 1) {
						StringBuilder sb = new StringBuilder(f_description.length);
						int offset = f_description.length - 1;
						for( int des = 0; des < offset; des++ )
						{
						    sb.append(f_description[des]).append(",");
						}
						sb.append(f_description[offset]);
						method.setDescription(sb.toString());
						
						StringBuilder sbs = new StringBuilder(f_sig.length);
						int offsets = f_sig.length - 1;
						for( int sig = 0; sig < offsets; sig++ )
						{
							sbs.append(f_sig[sig]).append(",");
						}
						sbs.append(f_sig[offsets]);
						method.setMethodSigniture(sbs.toString());
					}else {
						method.setDescription(f_description[i].trim());
						method.setMethodSigniture(f_sig[i]);
					}
					
					//method.setDescription(f_description[i].trim());
					method.setDepType(f_params_id[i].trim());
					method.setName(f_name[i].trim());
					DomainEntity type = domainEntityService.getDomainEntityById(re_type[i]);
					method.setReturnType(type);
					method.setcInterface(temp);
					//method.setMethodSigniture(f_sig[i]);
					interfaceMethodService.addInterfaceMethod(method);
				}
			}
			logger.info("添加 component interface:" + new Date().toString()
					+ "----end");
			return "redirect:/interface/"+uri;
		}else {
			return "error";
		}
	}

	@RequestMapping(value = "/add", method = RequestMethod.GET)
	public ModelAndView addComponentInterface() {
		ModelAndView model = new ModelAndView();
		model.setViewName("add_interface");
		try {
			List<DataType> _typeList = dataTypeService.getDataTypeList();
			List<DomainEntity> typeList = domainEntityService.getAllDomainEntity();
			typeList.addAll(_typeList);
			model.addObject("typeList", typeList);
			return model;
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return model;
	}

	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public String addComponentInterface(ComponentInterface cInterface,
			@RequestParam(required = false) long[] re_type,
			@RequestParam(required = false) String[] f_name,
			@RequestParam(required = false ,value = "f_params") String[] f_params,
			@RequestParam(required = false ) String[] f_sig,
			@RequestParam(required = false) String[] f_params_id,
			@RequestParam(required = false) String[] f_description) {
		logger.info("添加 component interface:" + new Date().toString()
				+ "----start");
//		for (int i = 0; i < re_type.length; i++) {
//			System.out.println(re_type[i]);
//		}
//		for (int i = 0; i < f_name.length; i++) {
//			System.out.println(f_name[i]);
//		}
//		for (int i = 0; i < f_params.length; i++) {
//			System.out.println(""+i+":"+f_params[i]);
//		}
//		for (int i = 0; i < f_params_id.length; i++) {
//			System.out.println(f_params_id[i]);
//		}
		Subject user = SecurityUtils.getSubject();
		if (user!= null) {
			CommonVariableModel model = (CommonVariableModel) user.getPrincipals()
					.getPrimaryPrincipal();
			cInterface.setOwner(model.getUser());
		}else {
			System.out.println("no user logined");
		}
		componentInterfaceService.addComponentInterface(cInterface);
		if (re_type != null && f_name != null && f_params != null
				&& f_description != null && re_type.length == f_name.length) {
			for (int i = 0; i < f_name.length; i++) {
				InterfaceMethod method = new InterfaceMethod();
				String[] params = f_params[i].split(";");
				StringBuffer temp = new StringBuffer();
				if (params!= null && params.length>0) {	
					temp.append(params[0]);
					for (int j = 1; j < params.length; j++) {
						temp.append(","+params[j].trim());
					}
				}
				method.setArguments(temp.toString());
				method.setDepType(f_params_id[i].trim());
				/**
				 * 当函数只有一个时，对于带有逗号的字段，springmvc会自动转为字符串，需要手动将其重新拼接
				 */
				if (f_name.length == 1) {
					StringBuilder sb = new StringBuilder(f_description.length);
					int offset = f_description.length - 1;
					for( int des = 0; des < offset; des++ )
					{
					    sb.append(f_description[des]).append(",");
					}
					sb.append(f_description[offset]);
					method.setDescription(sb.toString());
					
					StringBuilder sbs = new StringBuilder(f_sig.length);
					int offsets = f_sig.length - 1;
					for( int sig = 0; sig < offsets; sig++ )
					{
						sbs.append(f_sig[sig]).append(",");
					}
					sbs.append(f_sig[offsets]);
					method.setMethodSigniture(sbs.toString());
				}else {
					method.setDescription(f_description[i].trim());
					method.setMethodSigniture(f_sig[i]);
				}
				

				method.setName(f_name[i].trim());
				DomainEntity type = domainEntityService.getDomainEntityById(re_type[i]);
				method.setReturnType(type);
				method.setcInterface(cInterface);
				interfaceMethodService.addInterfaceMethod(method);
			}
		}
		logger.info("添加 component interface:" + new Date().toString()
				+ "----end");
		return "redirect:/" + cInterface.getUri().replace(":", "/");
	}
}
